﻿using System;
using System.Runtime.InteropServices;
using Odin.Contracts.Data;

namespace Odin.Execution.Utils
{
	// Code from http://www.codeproject.com/KB/cs/windowhider.aspx


	/// <summary>
	/// Object used to control a Windows Form.
	/// </summary>
	public class Window : IWindow
	{
		/// <summary>
		/// Win32 API Imports
		/// </summary>
		[DllImport("user32.dll")]
		private static extern
			bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
		[DllImport("user32.dll")]
		private static extern
			bool SetForegroundWindow(IntPtr hWnd);
		[DllImport("user32.dll")]
		private static extern
			bool IsIconic(IntPtr hWnd);
		[DllImport("user32.dll")]
		private static extern
			bool IsZoomed(IntPtr hWnd);
		[DllImport("user32.dll")]
		private static extern
			IntPtr GetForegroundWindow();
		[DllImport("user32.dll")]
		private static extern
			IntPtr GetWindowThreadProcessId(IntPtr hWnd, out IntPtr ProcessId);
		[DllImport("user32.dll")]
		private static extern
			IntPtr AttachThreadInput(IntPtr idAttach, IntPtr idAttachTo, int fAttach);

		/// <summary>

		/// Win32 API Constants for ShowWindowAsync()

		/// </summary>

		private const int SW_HIDE = 0;
		private const int SW_SHOWNORMAL = 1;
		private const int SW_SHOWMINIMIZED = 2;
		private const int SW_SHOWMAXIMIZED = 3;
		private const int SW_SHOWNOACTIVATE = 4;
		private const int SW_RESTORE = 9;
		private const int SW_SHOWDEFAULT = 10;

		/// <summary>

		/// Private Fields

		/// </summary>

		private IntPtr m_hWnd;
		private string m_Title;
		private bool m_Visible = true;
		private string m_Process;
		private bool m_WasMax = false;

		/// <summary>

		/// Window Object's Public Properties

		/// </summary>

		public IntPtr hWnd
		{
			get { return m_hWnd; }
		}
		public string Title
		{
			get { return m_Title; }
		}
		public string Process
		{
			get { return m_Process; }
		}
		public int ProcessId
		{
			get
			{
				var processId = GetProcessId();
				return processId.ToInt32();
			}
		}

		/// <summary>

		/// Sets this Window Object's visibility

		/// </summary>

		public bool Visible
		{
			get { return m_Visible; }
			set
			{
				//show the window

				if (value == true)
				{
					if (m_WasMax)
					{
						if (ShowWindowAsync(m_hWnd, SW_SHOWMAXIMIZED))
							m_Visible = true;
					}
					else
					{
						if (ShowWindowAsync(m_hWnd, SW_SHOWNORMAL))
							m_Visible = true;
					}
				}
				//hide the window

				if (value == false)
				{
					m_WasMax = IsZoomed(m_hWnd);
					if (ShowWindowAsync(m_hWnd, SW_HIDE))
						m_Visible = false;
				}
			}
		}

		/// <summary>

		/// Constructs a Window Object

		/// </summary>

		/// <param name="Title">Title Caption</param>

		/// <param name="hWnd">Handle</param>

		/// <param name="Process">Owning Process</param>

		public Window(string Title, IntPtr hWnd, string Process)
		{
			m_Title = Title;
			m_hWnd = hWnd;
			m_Process = Process;
		}

		//Override ToString() 

		public override string ToString()
		{
			//return the title if it has one, if not return the process name

			if (m_Title.Length > 0)
			{
				return m_Title;
			}
			else
			{
				return m_Process;
			}
		}


		public IntPtr GetProcessId()
		{
			IntPtr ProcessId = IntPtr.Zero;
			IntPtr ThreadID2 = GetWindowThreadProcessId(m_hWnd, out ProcessId);
			
			return ProcessId;
		}

		/// <summary>

		/// Sets focus to this Window Object

		/// </summary>

		public void Activate()
		{
			if (m_hWnd == GetForegroundWindow())
				return;

			IntPtr ProcessId = IntPtr.Zero;
			IntPtr ThreadID1 = GetWindowThreadProcessId(GetForegroundWindow(), out ProcessId);
			IntPtr ThreadID2 = GetWindowThreadProcessId(m_hWnd, out ProcessId);

			if (ThreadID1 != ThreadID2)
			{
				AttachThreadInput(ThreadID1, ThreadID2, 1);
				SetForegroundWindow(m_hWnd);
				AttachThreadInput(ThreadID1, ThreadID2, 0);
			}
			else
			{
				SetForegroundWindow(m_hWnd);
			}

			if (IsIconic(m_hWnd))
			{
				ShowWindowAsync(m_hWnd, SW_RESTORE);
			}
			else
			{
				ShowWindowAsync(m_hWnd, SW_SHOWNORMAL);
			}
		}
	}
}
